// 内置类型
// Partial, Required, Readonly 修饰类型的
// Pick, Omit 处理数据
// Exclude Extract 处理结合类型的
// Paramters ReturnValue infer
// 字符串类型 模板字符串 `${}` + infer

// 根据值类型（挑选/忽略）对象类型的属性
interface Person {
    name: string;
    age: number;
    address: string;
}

// 如何通过值拿到对应的key(先找到所有的值都是string)
// 将类型相同的进行映射 {name:"name", age: "never", address: "address"}
// name | never | address -> name | address
// Pick 这个属性即可
// 判断两个类型是否相同 （类型层级，结构）
type isEqual<T, K, Success, Fail> = [T] extends [K] ? [K] extends [T] ? Success : Fail: Fail; // 从类型的角度出发，两个类型完全一致
type ExtractKeys<T extends object, U, O=false> = {
    // 通过公共放入方法来进行判断
    [K in keyof T]: isEqual<T[K], U, isEqual<O, true, never, K>, isEqual<O, true, K, never>>
}[keyof T];

type PickKeysByValue<T extends Object, U>=Pick<T,ExtractKeys<T, U>>;
type OmitKeysByValue<T extends Object, U>=Pick<T,ExtractKeys<T, U, true>>;

type p2 = PickKeysByValue<Person,string>;
type p3 = OmitKeysByValue<Person,string>;

// 模板字符串 里面有一个很重要的功能，重映射
type PickKeysByValue2<T,U> = {
// 直接将对象的属性给忽略掉了
// 循环对象的key，看值的类型是否相同，如果相同留下这个key
  [K in keyof T as T[K] extends U ? K : never]: T[K]
}

type p4 = PickKeysByValue2<Person,string>


export {}
